// Function overload test suite focusing on value vs reference semantics

type Player struct {
    name String
    score int
}

func sum(a int, b int) int {
    return a + b
}

func sum(a float64, b float64) float64 {
    return a + b
}

func sum(a &int, b &int) int {
    return a + b
}

func mix(value int) int {
    return value
}

func mix(first int, second int) int {
    return first * 10 + second
}

func mix(a int, b int, c int) int {
    return a + b + c
}

func adjust(value int) int {
    return value + 1
}

func adjust(value &int) int {
    value = value + 100
    return value
}

func describe(value String) String {
    return "string:" + value
}

func describe(value &String) String {
    return "string-ref:" + value
}

func describe(values Vec<String>) String {
    if values.len() == 0 {
        return "string-vec:empty"
    }
    var last_index int = values.len() - 1
    return values[0] + "|" + values[last_index]
}

func describe(values Vec<int>) String {
    if values.len() == 0 {
        return "int-vec:empty"
    }
    return "int-vec"
}

func describe(player Player) String {
    return "player:" + player.name
}

func describe(player &Player) String {
    player.score = player.score + 5
    return "player-ref:" + player.name
}

func test_function_overload_suite() {
    println("=== Function Overload Test ===")

    // Integer sum overload
    var int_total int = sum(2, 5)
    assert(int_total == 7, "sum(int, int) should add integers")

    // Float sum overload
    var float_total float64 = sum(1.5, 2.5)
    assert(float_total == 4.0, "sum(float64, float64) should add floats")

    // Reference sum overload
    var left int = 10
    var right int = 20
    var ref_left &int = &left
    var ref_right &int = &right
    var ref_total int = sum(ref_left, ref_right)
    assert(ref_total == 30, "sum(&int, &int) should read referenced values")

    // Arity-based overloads
    assert(mix(7) == 7, "mix(int) should return the argument")
    assert(mix(3, 4) == 34, "mix(int, int) should encode digits")
    assert(mix(1, 2, 3) == 6, "mix(int, int, int) should sum all values")

    // Reference vs value adjustments
    var base int = 5
    var ref_base &int = &base
    var direct_result int = adjust(base)
    assert(direct_result == 6, "adjust(int) should increment by 1")
    assert(base == 5, "adjust(int) should not mutate the original value")

    var ref_result int = adjust(ref_base)
    assert(ref_result == 105, "adjust(&int) should add 100 and return new value")
    assert(base == 105, "adjust(&int) should mutate the referenced value")

    // String overloads
    var phrase String = "Nova"
    var phrase_summary String = describe(phrase)
    assert(phrase_summary == "string:Nova", "describe(String) should label the text")

    var phrase_ref &String = &phrase
    var phrase_ref_summary String = describe(phrase_ref)
    assert(phrase_ref_summary == "string-ref:Nova", "describe(&String) should use ref label")

    // Vector overloads
    var words Vec<String> = Vec<String>{}
    words.push("sunrise")
    words.push("midday")
    words.push("sunset")
    var string_vec_summary String = describe(words)
    assert(string_vec_summary == "sunrise|sunset", "describe(Vec<String>) should join ends")

    var measurements Vec<int> = Vec<int>{1, 2, 3}
    var int_vec_summary String = describe(measurements)
    assert(int_vec_summary == "int-vec", "describe(Vec<int>) should hit int vector overload")

    // Struct overloads
    var scout Player = Player {
        name: "Scout",
        score: 40,
    }
    var player_summary String = describe(scout)
    assert(player_summary == "player:Scout", "describe(Player) should read player name")

    var scout_ref &Player = &scout
    var player_ref_summary String = describe(scout_ref)
    assert(player_ref_summary == "player-ref:Scout", "describe(&Player) should use ref label")
    assert(scout.score == 45, "describe(&Player) should mutate player score")

    println("All overload assertions passed")
}
